#include "openglwidget.h"
#include <gwavi.h>
#include <QOpenGLFunctions>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QMouseEvent>
#include <QtMath>
#include <QPainter>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QFileDialog>
#include <QDir>
#include <QFileInfoList>
#include <QTimer>
#include <QFileDialog>
#include <QLinearGradient>
#include <QPaintEngine>
#include <QPainter>

#include <QDebug>

OpenGLWidget::OpenGLWidget(QWidget* parent):QOpenGLWidget(parent)
{
    m_Background.setRgbF(0.15,0.15,0.15);

    m_ForeColor = QColor(0,0,0);

    mWellColorMap.maxColor.setNamedColor("purple");
    mWellColorMap.minColor.setNamedColor("green");
    mWellColorMap.mapLevels = 15;

    mCurIndex = 0;
    IsDisplayString = IsDisplayWell = true;
    IsDisplayAxis = IsDisplayGrid = false;
    isDisplayLegend =false;
    viewDialog = Q_NULLPTR;
    colorW = Q_NULLPTR;
    m_LstCustomData = new QList<CustomData>();
    m_lstImageData =  new QList<QImage>();
    timer = new QTimer;
    timer->setInterval(200);

    connect(timer,&QTimer::timeout,this,&OpenGLWidget::DisplayAnimation);
    createActions();
}

OpenGLWidget::~OpenGLWidget()
{
}

void  OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_SMOOTH);
    glEnable(GL_MULTISAMPLE);
    //    glEnable(GL_BLEND);
    //    glBlendFunc(GL_SRC_ALPHA,GL_ONE);

    //glEnable(GL_LIGHTING);

    initShaders();
    //initTextures();

    //    shaderProgram->setUniformValue("lightPosition",QVector3D(0.0,0.0,-100.0));
    //    shaderProgram->setUniformValue("eyeDirection",QVector3D(0,0,1));
    //    shaderProgram->setUniformValue("constantAttenuation",1.0f);
    //    shaderProgram->setUniformValue("linearAttenuation",0.0f);
    //    shaderProgram->setUniformValue("quadraticAttenuation",0.0f);

    //    shaderProgram->setUniformValue("ambient",QVector3D(0.05,0.05,0.05));
    //    shaderProgram->setUniformValue("lightColor",QVector3D(0.33f, 0.42f, 0.18f));
    //    shaderProgram->setUniformValue("shininess",32);
    //    shaderProgram->setUniformValue("strength",150);

    //    shaderProgram->setUniformValue("materialProperty.ambient",QVector3D(0.05,0.05,0.05));
    //    shaderProgram->setUniformValue("materialProperty.diffuse",QVector3D(0.8,0.8,0.8));
    //    shaderProgram->setUniformValue("materialProperty.emission",QVector3D(0.05,0.05,0.05));
    //    shaderProgram->setUniformValue("materialProperty.specular",QVector3D(0.0,0.0,0.0));
    //    shaderProgram->setUniformValue("materialProperty.shininess",150);

    colorLocation = shaderProgram->attributeLocation("a_color");

    stringGeometryEngine = new GeometryEngine;
    wellGeometryEngine = new GeometryEngine;

    rotation = QQuaternion::fromAxisAndAngle(QVector3D(1,0,0), 90) * rotation;
    rotation = QQuaternion::fromAxisAndAngle(QVector3D(0,1,0), 0) * rotation;
    rotation = QQuaternion::fromAxisAndAngle(QVector3D(0,0,1), 0) * rotation;

}

void  OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glClearColor(m_Background.redF(),m_Background.greenF(),m_Background.blueF(),m_Background.alphaF());

    displayAxis();
    displayGrid();

    QMatrix4x4 matrix;
    matrix.translate(0.0, 0.0, -3);
    matrix.rotate(rotation);
    shaderProgram->setUniformValue("matrix" , projection * matrix * m_matS);

    if(IsDisplayString && IsDisplayWell)
    {
        //        shaderProgram->setUniformValue("textureString", 0);
        //        textureString->bind();

        //glVertexAttrib4f(colorLocation,m_StringColor.redF(),m_StringColor.greenF(),m_StringColor.blueF(),m_StringColor.alphaF());
        shaderProgram->setUniformValue("alpha" , 1.0f);
        stringGeometryEngine->drawCubeGeometry(shaderProgram);

        //        textureString->release();

        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA,GL_ONE);

        //        shaderProgram->setUniformValue("textureWell", 1);
        //        textureWell->bind(1);

        //glVertexAttrib4f(colorLocation,m_WellColor.redF(),m_WellColor.greenF(),m_WellColor.blueF(),m_WellColor.alphaF());
        //        program->enableAttributeArray(colorLocation);
        //        program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
        shaderProgram->setUniformValue("alpha" ,wellColorAlpha);
        wellGeometryEngine->drawCubeGeometry(shaderProgram);

        //        textureWell->release();

        glDisable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
    }
    else if(IsDisplayString)
    {
        glDisable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
        //        shaderProgram->setUniformValue("textureString", 0);
        //        textureString->bind();
        //glVertexAttrib4f(colorLocation,m_StringColor.redF(),m_StringColor.greenF(),m_StringColor.blueF(),m_StringColor.alphaF());
        shaderProgram->setUniformValue("alpha" , 1.0f);
        stringGeometryEngine->drawCubeGeometry(shaderProgram);

        //        textureString->release();
    }
    else if(IsDisplayWell)
    {
        glDisable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
        //        shaderProgram->setUniformValue("textureWell", 1);
        //        textureWell->bind(1);
        //glVertexAttrib4f(colorLocation,m_WellColor.redF(),m_WellColor.greenF(),m_WellColor.blueF(),m_WellColor.alphaF());
        shaderProgram->setUniformValue("alpha" , 1.0f);
        wellGeometryEngine->drawCubeGeometry(shaderProgram);

        //        textureWell->release();
    }

    displayLegend();
}

void  OpenGLWidget::resizeGL(int w, int h)
{
    //    // Calculate aspect ratio
    qreal aspect = qreal(w) / qreal(h);

    //    // Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
    const qreal zNear =0.1, zFar = 1000, fov = 45.0;

    //    // Reset projection
    projection.setToIdentity();

    //    // Set perspective projection
    projection.perspective(fov, aspect, zNear, zFar);
}

void OpenGLWidget::AddData(CustomData data)
{
    m_CurrentData = data;
    if(data.IsExistStringData())
    {
        ColorMap curMap = mFEMColorMap.value(m_CurrentStringParam);
        stringGeometryEngine->addVectorData(&m_CurrentData,true,false,mWellColorMap);
        stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,curMap);
    }
    if(data.IsExistWellData())
    {
        wellGeometryEngine->addVectorData(&m_CurrentData,false,false,mWellColorMap);
    }

    update();
}

void OpenGLWidget::mousePressEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
    {
        mousePressPos= QVector2D(e->localPos());
    }
}

void OpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton)
    {
        // Mouse release position - mouse press position
        QVector2D mouseMovePos(event->localPos());

        // Rotation axis is perpendicular to the mouse position difference
        // vector
        QVector3D diff = (mouseMovePos- mousePressPos).toVector3D();
        float dis = mouseMovePos.distanceToPoint(mousePressPos);

        float xAngle = qAsin(diff.x()/dis);
        float yAngle = qAsin(diff.y()/dis);
        float zAngle = qAcos(diff.z()/dis);

        rotation = QQuaternion::fromAxisAndAngle(QVector3D(1,0,0), xAngle) * rotation;
        rotation = QQuaternion::fromAxisAndAngle(QVector3D(0,1,0), yAngle) * rotation;
        rotation = QQuaternion::fromAxisAndAngle(QVector3D(0,0,1), zAngle) * rotation;

        update();
    }
}

void OpenGLWidget::wheelEvent(QWheelEvent *event)
{
    if(event->delta()>0)
    {
        m_matS.scale(1.05);
    }
    else
    {
        m_matS.scale(1/1.05);
    }
    update();
}

void OpenGLWidget::contextMenuEvent(QContextMenuEvent *event)
{
    popMenu->exec(QCursor::pos());
    event->accept();
}


void OpenGLWidget::createActions()
{
    popMenu = new QMenu();

    setFigureAction = new QAction("Adjust Figure",this);
    popMenu->addAction(setFigureAction);


    connect(setFigureAction,&QAction::triggered,this,&OpenGLWidget::showSetFigureDialog);
}

void OpenGLWidget::createDialog()
{
    if(viewDialog != Q_NULLPTR)
        return;
    viewDialog = new QDialog(this);
    viewDialog->setWindowTitle("View Configuration");

    lbBackColor = new QLabel("Back Color:");
    lbForeColor = new QLabel("Fore Color:");

    //lbStringColor = new QLabel("String Color:");
    //lbWellColor = new QLabel("Well Color:");

    cbBoxBackColor =  new QComboBox;
    fillColorList(cbBoxBackColor);
    cbBoxForeColor = new QComboBox;
    fillColorList(cbBoxForeColor);

    //    cbBoxStringColor =  new QComboBox;
    //    fillColorList(cbBoxStringColor);
    //    cbBoxWellColor = new QComboBox;
    //    fillColorList(cbBoxWellColor);

    QGridLayout *layout1 = new QGridLayout;
    layout1->addWidget(lbBackColor,0,0);
    layout1->addWidget(cbBoxBackColor,0,1);
    layout1->addWidget(lbForeColor,1,0);
    layout1->addWidget(cbBoxForeColor,1,1);

    QGroupBox *gpBoxBase = new QGroupBox;
    gpBoxBase->setTitle("Base Color");
    gpBoxBase->setLayout(layout1);

    lbStringMapMin = new QLabel("Min Color:");
    lbStringMapMax = new QLabel("Max Color");
    lbStringMapLevels = new QLabel("Map Levels:");

    cbBoxStringMapMin = new QComboBox;
    fillColorList(cbBoxStringMapMin);
    cbBoxStringMapMax = new QComboBox;
    fillColorList(cbBoxStringMapMax);

    spinBoxStringLevels = new QSpinBox;
    spinBoxStringLevels->setValue(15);
    spinBoxStringLevels->setRange(4,100);

    QGridLayout *layout2 = new QGridLayout;

    //    layout2->addWidget(lbStringColor,0,0);
    //    layout2->addWidget(cbBoxStringColor,0,1);
    //    layout2->addWidget(lbWellColor,1,0);
    //    layout2->addWidget(cbBoxWellColor,1,1);

    layout2->addWidget(lbStringMapMin,0,0);
    layout2->addWidget(cbBoxStringMapMin,0,1);
    layout2->addWidget(lbStringMapMax,1,0);
    layout2->addWidget(cbBoxStringMapMax,1,1);
    layout2->addWidget(lbStringMapLevels,2,0);
    layout2->addWidget(spinBoxStringLevels,2,1);

    QGroupBox *gbMap = new QGroupBox;
    gbMap->setTitle("String Map Color");
    gbMap->setLayout(layout2);

    lbWellMapLevels = new QLabel("Map Levels:");
    spinBoxWellLevels = new QSpinBox;
    spinBoxWellLevels->setValue(15);
    spinBoxWellLevels->setMinimum(4);
    spinBoxWellLevels->setMaximum(100);

    lbWellMapMin=new QLabel("Min Color:");
    lbWellMapMax=new  QLabel("Max Color:");
    lbWellMapAplha = new QLabel("Alpha:");

    cbBoxWellMapMin = new QComboBox;
    fillColorList(cbBoxWellMapMin);
    cbBoxWellMapMax =  new QComboBox;
    fillColorList(cbBoxWellMapMax);

    sliderWellAlpha = new QSlider(Qt::Horizontal);
    sliderWellAlpha->setRange(1,100);
    sliderWellAlpha->setValue(50);

    QGridLayout *layout4 = new QGridLayout;
    layout4->addWidget(lbWellMapMin,0,0);
    layout4->addWidget(cbBoxWellMapMin,0,1);
    layout4->addWidget(lbWellMapMax,1,0);
    layout4->addWidget(cbBoxWellMapMax,1,1);
    layout4->addWidget(lbWellMapLevels,2,0);
    layout4->addWidget(spinBoxWellLevels,2,1);
    layout4->addWidget(lbWellMapAplha,3,0);
    layout4->addWidget(sliderWellAlpha,3,1);
    QGroupBox *gbWellMap = new QGroupBox;
    gbWellMap->setTitle("Well Map Color");
    gbWellMap->setLayout(layout4);

    //    lbFEMMapParams = new QLabel("FEM Params:");
    //    cbBoxFEMParams = new QComboBox;

    //    lbFEMlMapMin =  new QLabel("Min Color:");
    //    cbBoxFEMMapMin = new QComboBox;
    //    fillColorList(cbBoxFEMMapMin);

    //    lbFEMMapMax = new QLabel("Max Color:");
    //    cbBoxFEMMapMax = new QComboBox;
    //    fillColorList(cbBoxFEMMapMax);

    //    lbFEMMapLevels = new QLabel("Map Levels:");
    //    spinBoxFEMLevels = new QSpinBox;
    //    spinBoxFEMLevels->setRange(4,100);
    //    spinBoxFEMLevels->setValue(15);

    //    QGridLayout *layout5 = new QGridLayout;
    //    layout5->addWidget(lbFEMMapParams,0,0);
    //    layout5->addWidget(cbBoxFEMParams,0,1);
    //    layout5->addWidget(lbFEMlMapMin,1,0);
    //    layout5->addWidget(cbBoxFEMMapMin,1,1);
    //    layout5->addWidget(lbFEMMapMax,2,0);
    //    layout5->addWidget(cbBoxFEMMapMax,2,1);
    //    layout5->addWidget(lbFEMMapLevels,3,0);
    //    layout5->addWidget(spinBoxFEMLevels,3,1);

    //    QGroupBox *gbFEMMap = new QGroupBox;
    //    gbFEMMap->setTitle("FEM Params Map Color");
    //    gbFEMMap->setLayout(layout5);

    ckBoxAxis = new QCheckBox;
    ckBoxAxis->setText("Axis");
    ckBoxGrid = new QCheckBox;
    ckBoxGrid->setText("Grid");
    ckBoxString = new QCheckBox;
    ckBoxString->setText("String");
    ckBoxWell = new QCheckBox;
    ckBoxWell->setText("Well");
    ckBoxLegend = new QCheckBox;
    ckBoxLegend->setText("Legend");

    QHBoxLayout *layout3 = new QHBoxLayout;
    layout3->addWidget(ckBoxAxis);
    layout3->addWidget(ckBoxGrid);
    layout3->addWidget(ckBoxString);
    layout3->addWidget(ckBoxWell);
    layout3->addWidget(ckBoxLegend);
    QGroupBox *gbOption = new QGroupBox;
    gbOption->setLayout(layout3);

    QVBoxLayout *mainLayout = new QVBoxLayout();
    mainLayout->addWidget(gpBoxBase);
    mainLayout->addWidget(gbMap);
    mainLayout->addWidget(gbWellMap);
    //    mainLayout->addWidget(gbFEMMap);
    mainLayout->addWidget(gbOption);

    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    viewDialog->setLayout(mainLayout);

    connect(cbBoxBackColor, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(cbBoxForeColor, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    //connect(cbBoxStringColor, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    //connect(cbBoxWellColor, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(cbBoxWellMapMax, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(cbBoxWellMapMin, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(spinBoxWellLevels,static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),this,&OpenGLWidget::setMapLevels);

    connect(cbBoxStringMapMin, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(cbBoxStringMapMax, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    connect(spinBoxStringLevels,static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),this,&OpenGLWidget::setMapLevels);

    //    connect(cbBoxFEMMapMin, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    //    connect(cbBoxFEMMapMax, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    //    connect(cbBoxFEMParams,static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),this,&OpenGLWidget::setColor);
    //    connect(spinBoxFEMLevels,static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),this,&OpenGLWidget::setMapLevels);

    connect(ckBoxAxis,&QCheckBox::clicked,this,&OpenGLWidget::setOptionEnable);
    connect(ckBoxGrid,&QCheckBox::clicked,this,&OpenGLWidget::setOptionEnable);
    connect(ckBoxString,&QCheckBox::clicked,this,&OpenGLWidget::setOptionEnable);
    connect(ckBoxWell,&QCheckBox::clicked,this,&OpenGLWidget::setOptionEnable);
    connect(ckBoxLegend, &QCheckBox::clicked, this, &OpenGLWidget::setOptionEnable);
    connect(sliderWellAlpha,&QSlider::valueChanged,this,&OpenGLWidget::setWellAlpha);
}

void OpenGLWidget::showSetFigureDialog()
{
    createDialog();

    ckBoxAxis->setChecked(IsDisplayAxis);
    ckBoxGrid->setChecked(IsDisplayGrid);
    ckBoxString->setChecked(IsDisplayString);
    ckBoxWell->setChecked(IsDisplayWell);

    QStringList colorList = QColor::colorNames();
    ColorMap curColorMap = mFEMColorMap.value(m_CurrentStringParam);
    for(int i=0;i<colorList.count();i++)
    {
        QColor tempColor(colorList[i]);
        if(m_Background.name() == tempColor.name())
        {
            cbBoxBackColor->setCurrentIndex(i);
        }

        if(m_ForeColor.name() == tempColor.name())
        {
            cbBoxForeColor->setCurrentIndex(i);
        }

        //        if(mStringColorMap.minColor.name() == tempColor.name())
        //        {
        //            cbBoxStringMapMin->setCurrentIndex(i);
        //        }

        //        if(mStringColorMap.maxColor.name() == tempColor.name())
        //        {
        //            cbBoxStringMapMax->setCurrentIndex(i);
        //        }

        if(curColorMap.minColor.name() == tempColor.name())
        {
            cbBoxStringMapMin->setCurrentIndex(i);
        }

        if(curColorMap.maxColor.name() == tempColor.name())
        {
            cbBoxStringMapMax->setCurrentIndex(i);
        }

        if(mWellColorMap.minColor.name() == tempColor.name())
        {
            cbBoxWellMapMin->setCurrentIndex(i);
        }

        if(mWellColorMap.maxColor.name() == tempColor.name())
        {
            cbBoxWellMapMax->setCurrentIndex(i);
        }
    }

    //    if(cbBoxFEMParams->count() == 0)
    //    {
    //        QList<QString> lstName =m_CurrentData.GetFEMParams();
    //        QStringList strList;

    //        mFEMColorMap.clear();

    //        QList<int> lstIndex;
    //        QList<QString> lstSubName;
    //        for(int i=0;i<lstName.count();i++)
    //        {
    //          QStringList  lstTemp = lstName.at(i).split('_');
    //          int index = lstTemp.at(lstTemp.count()-1).toInt();
    //          lstIndex.append(index);
    //          lstSubName.append(lstTemp.at(0));
    //        }

    //        for(int i=1;i<lstName.count();i++)
    //        {
    //            ColorMap tempMap;
    //            tempMap.minColor = Qt::red;
    //            tempMap.maxColor = Qt::blue;
    //            tempMap.mapLevels = 15;

    //            int index = lstIndex.indexOf(i);
    //            mFEMColorMap.insert(lstName[index],tempMap);
    //            strList<<lstSubName[index];
    //        }

    //        cbBoxFEMParams->addItems(strList);
    //    }
    viewDialog->setModal(false);
    viewDialog->show();
}

void OpenGLWidget::setColor(int index)
{
    QComboBox* cbBox = qobject_cast<QComboBox*> (sender());
    QStringList colorList = QColor::colorNames();

    QColor color =QColor(colorList[index]);
    if (cbBox ==cbBoxForeColor)
    {
        m_ForeColor  = color;
    }

    if(cbBox == cbBoxBackColor)
    {
        m_Background = color;

        QResizeEvent e = QResizeEvent(QSize(this->width(),this->height()),QSize(this->width(),this->height()));

        emit resizeEvent(&e);
    }

    //    if(cbBox == cbBoxStringColor)
    //    {
    //        m_StringColor = color;
    //    }

    //    if(cbBox == cbBoxWellColor)
    //    {
    //        m_WellColor = color;
    //        m_WellColor.setAlphaF(0.5);
    //    }

    if(cbBox == cbBoxStringMapMin)
    {
        ColorMap curMap = mFEMColorMap.value(m_CurrentStringParam);
        curMap.minColor = color;
        mFEMColorMap[m_CurrentStringParam] = curMap;
        if(m_CurrentData.IsExistStringData())
        {
            stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,curMap);
        }
    }

    if(cbBox == cbBoxStringMapMax)
    {
        //        mStringColorMap.maxColor = color;

        //        if(m_CurrentData.IsExistStringData())
        //        {
        //            stringGeometryEngine->setColorMapByZ(&m_CurrentData,true,mStringColorMap);
        //        }
        ColorMap curMap = mFEMColorMap.value(m_CurrentStringParam);
        curMap.maxColor = color;
        mFEMColorMap[m_CurrentStringParam] = curMap;

        if(m_CurrentData.IsExistStringData())
        {

            stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,curMap);

        }
    }

    if(cbBox == cbBoxWellMapMax)
    {
        mWellColorMap.maxColor = color;

        if(m_CurrentData.IsExistWellData())
        {
            wellGeometryEngine->setColorMapByZ(&m_CurrentData,false,mWellColorMap);
        }
    }

    if(cbBox == cbBoxWellMapMin)
    {
        mWellColorMap.minColor = color;

        if(m_CurrentData.IsExistWellData())
        {
            wellGeometryEngine->setColorMapByZ(&m_CurrentData,false,mWellColorMap);
        }
    }

    //    if(cbBox == cbBoxFEMMapMin)
    //    {
    //        int index = cbBoxFEMParams->currentIndex();
    //        QString paramName = cbBoxFEMParams->currentText()+"_"+QString::number(index+1);

    //        ColorMap colorMap = mFEMColorMap.value(paramName);
    //        colorMap.minColor = color;

    //        mFEMColorMap[paramName] = colorMap;
    //        if(m_CurrentData.IsExistStringData())
    //        {
    //            stringGeometryEngine->setColorMapByName(&m_CurrentData,paramName,mFEMColorMap.value(paramName));
    //        }
    //    }

    //    if(cbBox == cbBoxFEMMapMax)
    //    {
    //        int index = cbBoxFEMParams->currentIndex();
    //        QString paramName = cbBoxFEMParams->currentText()+"_"+QString::number(index+1);

    //        ColorMap colorMap = mFEMColorMap.value(paramName);
    //        colorMap.maxColor = color;

    //        mFEMColorMap[paramName] = colorMap;

    //        if(m_CurrentData.IsExistStringData())
    //        {
    //            stringGeometryEngine->setColorMapByName(&m_CurrentData,paramName,mFEMColorMap.value(paramName));
    //        }
    //    }

    //    if(cbBox == cbBoxFEMParams)
    //    {
    //        int index = cbBoxFEMParams->currentIndex();
    //        QString paramName = cbBoxFEMParams->currentText()+"_"+QString::number(index+1);

    //        ColorMap colorMap =  mFEMColorMap.value(paramName);

    //        QStringList colorList = QColor::colorNames();

    //        for(int i=0;i<colorList.count();i++)
    //        {
    //            QColor tempColor(colorList[i]);
    //            if(colorMap.minColor.name() == tempColor.name())
    //            {
    //                cbBoxFEMMapMin->setCurrentIndex(i);
    //            }

    //            if(colorMap.maxColor.name() == tempColor.name())
    //            {
    //                cbBoxFEMMapMax->setCurrentIndex(i);
    //            }
    //        }

    //        spinBoxFEMLevels->setValue(colorMap.mapLevels);

    //        if(m_CurrentData.IsExistStringData())
    //        {
    //            stringGeometryEngine->setColorMapByName(&m_CurrentData,paramName,mFEMColorMap.value(paramName));
    //        }
    //    }

    update();
}

void OpenGLWidget::setOptionEnable(bool enable)
{
    QCheckBox* ckBox = qobject_cast<QCheckBox*> (sender());

    if(ckBox == ckBoxAxis)
    {
        IsDisplayAxis = enable;
    }

    if(ckBox == ckBoxGrid)
    {
        IsDisplayGrid = enable;
    }

    if(ckBox == ckBoxString)
    {
        IsDisplayString = enable;
    }

    if(ckBox == ckBoxWell)
    {
        IsDisplayWell = enable;
        if(IsDisplayWell)
        {
            ckBoxLegend->setChecked(false);
            isDisplayLegend = false;
        }
    }

    if(ckBox == ckBoxLegend)
    {
        isDisplayLegend = enable;
        if(!m_CurrentData.IsExistStringData() || IsDisplayWell || !IsDisplayString)
        {
            ckBoxLegend->setChecked(false);
            isDisplayLegend = false;
        }
    }

    this->update();
}

void OpenGLWidget::setWellAlpha(int alpha)
{
    wellColorAlpha = alpha * 1.0 / 100;
    update();
}

void OpenGLWidget::AddMultiData(QList<CustomData> *lstData)
{
    m_LstCustomData = lstData;
}

void OpenGLWidget::setMapLevels(int levels)
{
    QSpinBox* spinBox = qobject_cast<QSpinBox*> (sender());

    if(spinBox == spinBoxStringLevels)
    {
        //        mStringColorMap.mapLevels = levels;

        //        if(m_CurrentData.IsExistStringData())
        //        {
        //            stringGeometryEngine->setColorMapByZ(&m_CurrentData,true,mStringColorMap);
        //        }

        ColorMap curMap = mFEMColorMap.value(m_CurrentStringParam);
        curMap.mapLevels = levels;
        mFEMColorMap[m_CurrentStringParam] = curMap;

        if(m_CurrentData.IsExistStringData())
        {
            stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,curMap);

        }
    }

    if(spinBox == spinBoxWellLevels)
    {
        mWellColorMap.mapLevels = levels;//spinBox->value();

        if(m_CurrentData.IsExistWellData())
        {
            wellGeometryEngine->setColorMapByZ(&m_CurrentData,false,mWellColorMap);
        }
    }

    //    if(spinBox == spinBoxFEMLevels)
    //    {
    //        int index = cbBoxFEMParams->currentIndex();
    //        QString paramName = cbBoxFEMParams->currentText()+"_"+QString::number(index+1);

    //        ColorMap colorMap = mFEMColorMap.value(paramName);
    //        colorMap.mapLevels = levels;
    //        mFEMColorMap[paramName] = colorMap;

    //        if(m_CurrentData.IsExistStringData())
    //        {
    //            stringGeometryEngine->setColorMapByName(&m_CurrentData,paramName,mFEMColorMap.value(paramName));
    //        }
    //    }

    update();
}

void OpenGLWidget::initShaders()
{
    shaderProgram = new QOpenGLShaderProgram;

    if(!shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex,":/vshader.vert"))
    {
        close();
    }

    if(!shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment,":/fshader.frag"))
    {
        close();
    }

    if(!shaderProgram->link())
        close();

    if(!shaderProgram->bind())
        close();
}

void OpenGLWidget::initTextures()
{
    QImage img(128,128,QImage::Format_RGBA8888);
    QPainter painter;

    QColor c= Qt::red;
    c.setAlphaF(0.7);

    painter.begin(&img);
    painter.fillRect(0,0,128,128,c);
    painter.end();

    textureWell = new QOpenGLTexture(img);

    // Set nearest filtering mode for texture minification
    textureWell->setMinificationFilter(QOpenGLTexture::Nearest);

    // Set bilinear filtering mode for texture magnification
    textureWell->setMagnificationFilter(QOpenGLTexture::Linear);

    // Wrap texture coordinates by repeating
    // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2)
    textureWell->setWrapMode(QOpenGLTexture::Repeat);

    c = Qt::green;
    painter.begin(&img);
    painter.fillRect(0,0,128,128,c);
    painter.end();

    textureString = new QOpenGLTexture(img);
    textureString->setMinificationFilter(QOpenGLTexture::Nearest);
    textureString->setMagnificationFilter(QOpenGLTexture::Linear);
    textureString->setWrapMode(QOpenGLTexture::Repeat);
}

void OpenGLWidget::displayAxis()
{
    if(!IsDisplayAxis)
    {
        return;
    }

    glLineWidth(2.0f);

    m_CurrentData.GetAxisInfo(xMin,xMax,yMin,yMax,zMin,zMax);
    GLfloat vertices[3][2][3] =
    {
        {{xMin,yMin,zMin},{xMax,yMin,zMin}},
        {{xMin,yMin,zMin},{xMin,yMax,zMin}},
        {{xMin,yMin,zMin},{xMin,yMin,zMax}}
    };

    vbo.create();
    vbo.bind();
    vbo.allocate(vertices,18*sizeof(GLfloat));

    GLuint vPosition = shaderProgram->attributeLocation("vPosition");
    shaderProgram->setAttributeBuffer(vPosition,GL_FLOAT,0,3,0);
    glEnableVertexAttribArray(vPosition);

    glVertexAttrib4f(colorLocation,m_ForeColor.redF(),m_ForeColor.greenF(),m_ForeColor.blueF(),m_ForeColor.alphaF());

    for(int i=0;i<3;i++)
    {
        glDrawArrays(GL_LINES,i*2,2);
    }

    shaderProgram->disableAttributeArray(vPosition);
    shaderProgram->disableAttributeArray(colorLocation);

    vbo.destroy();
}

void OpenGLWidget::displayGrid()
{
    if(!IsDisplayGrid)
    {
        return;
    }

    glLineWidth(1.0f);

    m_CurrentData.GetAxisInfo(xMin,xMax,yMin,yMax,zMin,zMax);

    float stepX =(xMax - xMin) / xGridNum;
    float stepY =(yMax - yMin) / yGridNum;
    float stepZ =(zMax - zMin) / zGridNum;

    if(stepX ==0)
        return;

    quint16 num = (xGridNum + yGridNum + zGridNum) * 2;
    QVector3D vecGrid[40][2];
    int index =0;
    for(int i=0;i<num;i++)
    {
        if(i < xGridNum)
        {
            index =i+1;
            vecGrid[i][0] = QVector3D(xMin + index * stepX, yMin, zMin);
            vecGrid[i][1] = QVector3D(xMin + index * stepX, yMax, zMin);
        }
        else if((i >= xGridNum) && (i< xGridNum *2))
        {
            index = i - xGridNum + 1;
            vecGrid[i][0] = QVector3D(xMin + index * stepX, yMin, zMin);
            vecGrid[i][1] = QVector3D(xMin + index * stepX, yMin, zMax);
        }
        else if((i >= xGridNum *2) && (i < xGridNum * 2+ yGridNum))
        {
            index = i - xGridNum *2 + 1;
            vecGrid[i][0] = QVector3D(xMin, yMin + index * stepY, zMin);
            vecGrid[i][1] = QVector3D(xMin, yMin + index * stepY, zMax);
        }
        else  if((i >= xGridNum * 2+ yGridNum) && (i < xGridNum * 2 + yGridNum *2))
        {
            index = i - (xGridNum * 2 + yGridNum) + 1;
            vecGrid[i][0] = QVector3D(xMin, yMin + index * stepY, zMin);
            vecGrid[i][1] = QVector3D(xMax, yMin + index * stepY, zMin);
        }
        else if((i >= xGridNum * 2 + yGridNum *2) && (i <  xGridNum * 2 + yGridNum *2 + zGridNum))
        {
            index = i - (xGridNum * 2 + yGridNum *2) + 1;
            vecGrid[i][0] = QVector3D(xMin, yMin, zMin + index * stepZ);
            vecGrid[i][1] = QVector3D(xMax, yMin, zMin + index * stepZ);
        }
        else
        {
            index = i - (xGridNum * 2 + yGridNum *2 + zGridNum) + 1;
            vecGrid[i][0] = QVector3D(xMin, yMin, zMin + index * stepZ);
            vecGrid[i][1] = QVector3D(xMin, yMax, zMin + index * stepZ);
        }
    }

	//for (int i = 0; i < vecGrid.count(); i++)
	//	qDebug() << vecGrid[i];

    vbo.create();
    vbo.bind();
    vbo.allocate(vecGrid,num*2*sizeof(QVector3D));

    GLuint vPosition = shaderProgram->attributeLocation("vPosition");
    shaderProgram->setAttributeBuffer(vPosition,GL_FLOAT,0,3,0);
    glEnableVertexAttribArray(vPosition);

    glVertexAttrib4f(colorLocation,m_ForeColor.redF(),m_ForeColor.greenF(),m_ForeColor.blueF(),m_ForeColor.alphaF());

    for(int i=0;i<num;i++)
    {
        glDrawArrays(GL_LINES,i*2,2);
    }

    shaderProgram->disableAttributeArray(vPosition);
    shaderProgram->disableAttributeArray(colorLocation);

    vbo.destroy();
}

void OpenGLWidget::displayLegend()
{
    if(IsDisplayString && isDisplayLegend && !IsDisplayWell)
    {
        if(colorW != nullptr)
        {
            colorW->hide();
        }

        //        qDebug()<<this->width();
        //        qDebug()<<this->height();
        int height = this->height()/2;
        int width = 80;//this->width()/14;
        int border = 10;
        if(colorW == nullptr)
        {
            colorW = new QWidget(this);
            colorW->setWindowOpacity(0.5);
            //colorW->setGeometry(this->width()-width-border,border,width,height);

            labelColor = new QLabel;

            QVBoxLayout *colorMapVBox = new QVBoxLayout;
            colorMapVBox->addWidget(labelColor);
            colorMapVBox->setSizeConstraint(QLayout::SetMinimumSize);
            delete colorW->layout();
            colorW->setLayout(colorMapVBox);
        }

        QLinearGradient gr(0, 0, 1, height-2 * border);
        ColorMap colorMap = mFEMColorMap.value(m_CurrentStringParam);

        float stepZ = 1.0/colorMap.mapLevels;

        float redStart = colorMap.minColor.redF();
        float blueStart = colorMap.minColor.blueF();
        float greenStart = colorMap.minColor.greenF();

        float redStop = colorMap.maxColor.redF();
        float blueStop = colorMap.maxColor.blueF();
        float greenStop = colorMap.maxColor.greenF();

        float redStep = (redStop - redStart) / colorMap.mapLevels;
        float greenStep = (greenStop - greenStart) / colorMap.mapLevels;
        float blueStep = (blueStop - blueStart) / colorMap.mapLevels;

        for(int k=0;k<colorMap.mapLevels+1;k++)
        {
            QColor c;

            float redCur = redStart + k * redStep;
            redCur = redCur > 1 ? 1 : redCur;
            redCur = redCur < 0 ? 0 : redCur;
            c.setRedF(redCur);

            float greenCur = greenStart + k * greenStep;
            greenCur = greenCur > 1 ? 1 : greenCur;
            greenCur = greenCur < 0 ? 0 : greenCur;
            c.setGreenF(greenCur);

            float blueCur = blueStart + k * blueStep;
            blueCur = blueCur > 1 ? 1 : blueCur;
            blueCur = blueCur < 0 ? 0 : blueCur;
            c.setBlueF(blueCur);

            float zCur = stepZ * k;
            zCur = zCur > 1 ? 1 : zCur;
            gr.setColorAt(zCur,c);

            //qDebug()<<k<<","<<redStart + k * redStep<<","<<greenStart + k * greenStep<<","<<blueStart + k * blueStep;
        }

        QPixmap pm(width, height);
        pm.fill(Qt::transparent);
        QPainter pmp(&pm);
        pmp.setBrush(QBrush(gr));
        //pmp.setPen(Qt::NoPen);
        pmp.drawRect(border, border, 20, height - 2*border);
        pmp.setPen(m_ForeColor);

        int step = (height -2*border)  / colorMap.mapLevels;
        for (int i = 0; i < colorMap.mapLevels+1; i++) {
            int yPos = i * step + border;
            //pmp.drawLine(border, yPos, 25, yPos);

            float zCur = stepZ * i;
            zCur = zCur > 1 ? 1 : zCur;
            pmp.drawText(40, yPos + 2, QString("%1").arg(zCur,2,'f',2));
        }

        labelColor->setPixmap(pm);
        colorW->show();
    }
    else
    {
        if(colorW != nullptr)
        {
            colorW->hide();
        }
    }
}

void OpenGLWidget::fillColorList(QComboBox *cbBox)
{
    QStringList colorList = QColor::colorNames();
    foreach (QString color, colorList) {
        //qDebug()<<color;
        QPixmap pix(QSize(100,20));
        pix.fill(QColor(color));
        cbBox->addItem(QIcon(pix),NULL);
        cbBox->setIconSize(QSize(100,20));
        cbBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
    }
}

void OpenGLWidget::DisplayAnimation()
{
    //    IsDisplayAxis = IsDisplayGrid = false;
    //    IsDisplayString = IsDisplayWell = true;

    m_CurrentData = m_LstCustomData->at(mCurIndex);

    if(m_CurrentData.IsExistStringData() && IsDisplayString)
    {
        ColorMap curMap = mFEMColorMap.value(m_CurrentStringParam);
        stringGeometryEngine->addVectorData(&m_CurrentData,true,true,curMap,lstRange);
        stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,curMap);
    }

    m_CurrentData = m_LstCustomData->last();//at(m_LstCustomData->count()-1);
    if(m_CurrentData.IsExistWellData() && IsDisplayWell)
    {
        wellGeometryEngine->addVectorData(&m_CurrentData,false,true,mWellColorMap,lstRange);
    }


    if(!isGetImageData)
    {
        if(mCurIndex == 0)
        {
            m_lstImageData = new QList<QImage>;
        }

        QImage image = this->grabFramebuffer();

//        QString filename = QString("E://%1.jpg").arg(mCurIndex,2,10,QChar('0'));
//        image.save(filename);

        m_lstImageData->append(image);
        if(mCurIndex == m_LstCustomData->count()-1)
        {
            isGetImageData = true;
        }
    }

    mCurIndex = (++ mCurIndex)%(m_LstCustomData->count());
    update();
}

void OpenGLWidget::triggerAnimation(bool isStop)
{
    if(!isStop)
    {
        isGetImageData= false;
        m_lstImageData->clear();

        mCurIndex = 0;

        if(m_LstCustomData->count() == 0)
            return;
        CustomData tempData = m_LstCustomData->first();//at(0);
        float xMin,xMax,yMin,yMax,zMin,zMax;

        tempData.GetWellRange(xMin,xMax,yMin,yMax,zMin,zMax);

        for(int i=1;i<m_LstCustomData->count();i++)
        {
            tempData = m_LstCustomData->at(i);
            float xTempMin,xTempMax,yTempMin,yTempMax,zTempMin,zTempMax;
            tempData.GetWellRange(xTempMin,xTempMax,yTempMin,yTempMax,zTempMin,zTempMax);

            xMin = xMin < xTempMin ? xMin : xTempMin;
            xMax =  xMax > xTempMax ? xMax : xTempMax;

            yMin =  yMin < yTempMin ? yMin : yTempMin;
            yMax =  yMax > yTempMax ? yMax : yTempMax;

            zMin =  zMin < zTempMin ? zMin : zTempMin;
            zMax = zMax > zTempMax ? zMax : zTempMax;
        }

        lstRange = new QList<float>();
        lstRange->append(xMin);
        lstRange->append(xMax);

        lstRange->append(yMin);
        lstRange->append(yMax);

        lstRange->append(zMin);
        lstRange->append(zMax);

        timer->start();
    }
    else
    {
        timer->stop();
    }
}

void OpenGLWidget::cbBoxFEMParamsChanged(int currentIndex)
{
    if(!m_CurrentData.IsExistStringData())
    {
        return;
    }

    QList<QString> lstName = m_CurrentData.GetFEMParams();
    QList<int> lstIndex;
    for(int i=0;i<lstName.count();i++)
    {
        QStringList  lstTemp = lstName.at(i).split('_');
        int index = lstTemp.last().toInt();//lstTemp.at(lstTemp.count()-1).toInt();
        lstIndex.append(index);
    }

    m_CurrentStringParam = lstName.at(lstIndex.indexOf(currentIndex));

    if(!mFEMColorMap.contains(m_CurrentStringParam))
    {
        ColorMap temp;

        temp.maxColor.setNamedColor("red");
        temp.minColor.setNamedColor("blue");
        temp.mapLevels = 15;

        mFEMColorMap.insert(m_CurrentStringParam,temp);
    }

    if(viewDialog != nullptr)
    {
        QStringList colorList = QColor::colorNames();
        ColorMap curColorMap = mFEMColorMap.value(m_CurrentStringParam);
        for(int i=0;i<colorList.count();i++)
        {
            QColor tempColor(colorList[i]);

            if(curColorMap.minColor.name() == tempColor.name())
            {
                cbBoxStringMapMin->setCurrentIndex(i);
            }

            if(curColorMap.maxColor.name() == tempColor.name())
            {
                cbBoxStringMapMax->setCurrentIndex(i);
            }
        }
    }

    stringGeometryEngine->setColorMapByName(&m_CurrentData,m_CurrentStringParam,mFEMColorMap.value(m_CurrentStringParam));
    update();
}

void OpenGLWidget::saveAnimation()
{
    if(m_lstImageData->count() ==0)
        return;

    QString newPath = QFileDialog::getSaveFileName(this, tr("Save Animation"),
                                                    "/example", tr("AVI files (*.AVI)"));

    if (newPath.isEmpty())
        return;

    GWAVI *gwAvi =  new GWAVI;
    gwAvi->AddImages(newPath,*m_lstImageData);
}
